<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 Subtyping and Inclusion Polymorphism
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora143.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora145.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> Subtyping and Inclusion Polymorphism</H2>
<A NAME="sec-sous-typage"></A>
<A NAME="@concepts331"></A>
<A NAME="@concepts332"></A>
<A NAME="@concepts333"></A>
Subtyping makes it possible for an object of some type to be considered and
used as an object of another type. An object type <I>ot2</I> could be a
subtype of <I>ot1</I> if:
<OL type=1>
<LI>
 it includes all of the methods of <I>ot1</I>,

<LI> each method of <I>ot2</I> that is a method of <I>ot1</I> is a
 subtype of the <I>ot1</I> method.
</OL>The subtype relation is only meaningful between objects: it can only be
expressed between objects. Furthermore, the subtype relation must always be
explicit. It is possible to indicate either that a type is a subtype of
another, or that an object has to be considered as an object of a super type.
<A NAME="@fonctions396"></A>


<H3> Syntax </H3> <HR>

<TABLE CELLSPACING=2 CELLPADDING=0>
<TR><TD  ALIGN=left NOWRAP><B>(</B><I>name</I> <B>:</B> <I>sub_type</I> <B>:&gt;</B> <I>super_type</I><B>)</B></TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><B>(</B><I>name</I> <B>:&gt;</B> <I>super_type</I><B>)</B></TD>
</TR></TABLE>


<HR>


<A NAME="toc211"></A>
<H3> Example</H3>
Thus we can indicate that an instance of <TT>colored_point</TT> can be used
as an instance of <TT>point</TT>:


<PRE><BR># <B>let</B><CODE> </CODE>pc<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>colored_point<CODE> </CODE><TT>(</TT><CODE>4</CODE><CODE>,</CODE><CODE>5</CODE><TT>)</TT><CODE> </CODE><CODE>"white"</CODE>;;<BR><CODE>val pc : colored_point = &lt;obj&gt;</CODE><BR># <B>let</B><CODE> </CODE>p1<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>pc<CODE> </CODE><CODE>:</CODE><CODE> </CODE>colored_point<CODE> </CODE><CODE>:&gt;</CODE><CODE> </CODE>point<TT>)</TT>;;<BR><CODE>val p1 : point = &lt;obj&gt;</CODE><BR># <B>let</B><CODE> </CODE>p2<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>pc<CODE> </CODE><CODE>:&gt;</CODE><CODE> </CODE>point<TT>)</TT>;;<BR><CODE>val p2 : point = &lt;obj&gt;</CODE><BR>

</PRE>
<BR>
<BR>
Although known as a point, <TT>p1</TT> is nevertheless a colored point, and
sending the method <TT>to_string</TT> will trigger the method relevant for
colored points: 


<PRE><BR># p1#to_string();;<BR><CODE>- : string = "( 4, 5) with color white"</CODE><BR>

</PRE>
<BR>
<BR>
This way, it is possible to build lists containing both points and colored
points:


<PRE><BR># <B>let</B><CODE> </CODE>l<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>[</CODE><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>2</CODE><TT>)</TT><CODE> </CODE>;<CODE> </CODE>p1<CODE>]</CODE><CODE> </CODE>;;<BR><CODE>val l : point list = [&lt;obj&gt;; &lt;obj&gt;]</CODE><BR># List.iter<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>x<CODE> </CODE>-&gt;<CODE> </CODE>x#print();<CODE> </CODE>print_newline()<TT>)</TT><CODE> </CODE>l;;<BR><CODE>( 1, 2)</CODE><BR><CODE>( 4, 5) with color white</CODE><BR><CODE>- : unit = ()</CODE><BR>

</PRE>
<BR>
<BR>
Of course, the actions that can be performed on the objects of such a list are
restricted to those allowed for points.


<PRE><BR># p1#get_color<CODE> </CODE>()<CODE> </CODE>;;<BR><CODE>Characters 1-3:</CODE><BR><CODE>This expression has type point</CODE><BR><CODE>It has no method get_color</CODE><BR>

</PRE>
<BR>
<BR>
The combination of delayed binding and subtyping provides a new form of
polymorphism: inclusion polymorphism. This is the ability to handle
values of any type having a subtype relation with the expected type.
Although static typing information guarantees that sending a message will always find
the corresponding method, the behavior of the method depends on the
actual receiving object.<BR>
<BR>
<A NAME="toc212"></A>
<H3> Subtyping is not Inheritance</H3>
Unlike mainstream object-oriented languages such as C++, Java,
and SmallTalk, subtyping and inheritance are different concepts in
Objective CAML. There are two main reasons for this.
<OL type=1>
<LI>
 Instances of the class <TT>c2</TT> may have a type that is a subtype of
 the object type <TT>c1</TT> even if the class <TT>c2</TT> does not inherit
 from the class <TT>c1</TT>.
 Indeed, the class <TT>colored_point</TT> can be defined independently from
 the class <TT>point</TT>, provided the type of its instances are constrained to
 the object type <TT>point</TT>.

<LI> Class <TT>c2</TT> may inherit from the class <TT>c1</TT> but have
 instances whose type is not a subtype of the object type <TT>c1</TT>. This is
 illustrated in the following example, which uses the ability to define an
 abstract method that takes an as yet undetermined instance as an argument of
 the class being defined. In our example, this is method <TT>eq</TT> of class
 <TT>equal</TT>.
</OL>

<PRE><BR># <B>class</B><CODE> </CODE><B>virtual</B><CODE> </CODE>equal<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>object</B><TT>(</TT>self<CODE>:</CODE><I>'a</I><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE><B>virtual</B><CODE> </CODE>eq<CODE> </CODE><CODE>:</CODE><CODE> </CODE><I>'a</I><CODE> </CODE>-&gt;<CODE> </CODE>bool<BR><CODE> </CODE><CODE> </CODE><B>end</B>;;<BR><CODE>class virtual equal : unit -&gt; object ('a) method virtual eq : 'a -&gt; bool end</CODE><BR># <B>class</B><CODE> </CODE>c1<CODE> </CODE><TT>(</TT>x0<CODE>:</CODE>int<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>object</B><TT>(</TT>self<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>equal<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get_x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>eq<CODE> </CODE>o<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>self#get_x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>o#get_x<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><B>end</B>;;<BR><CODE>class c1 :</CODE><BR><CODE>  int -&gt;</CODE><BR><CODE>  object ('a) val x : int method eq : 'a -&gt; bool method get_x : int end</CODE><BR># <B>class</B><CODE> </CODE>c2<CODE> </CODE><TT>(</TT>x0<CODE>:</CODE>int<TT>)</TT><CODE> </CODE><TT>(</TT>y0<CODE>:</CODE>int<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>object</B><TT>(</TT>self<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>equal<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE>c1<CODE> </CODE>x0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>y0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>get_y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>y<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>eq<CODE> </CODE>o<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>self#get_x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>o#get_x<TT>)</TT><CODE> </CODE><CODE>&amp;&amp;</CODE><CODE> </CODE><TT>(</TT>self#get_y<CODE> </CODE><CODE>=</CODE><CODE> </CODE>o#get_y<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><B>end</B>;;<BR><CODE>class c2 :</CODE><BR><CODE>  int -&gt;</CODE><BR><CODE>  int -&gt;</CODE><BR><CODE>  object ('a)</CODE><BR><CODE>    val x : int</CODE><BR><CODE>    val y : int</CODE><BR><CODE>    method eq : 'a -&gt; bool</CODE><BR><CODE>    method get_x : int</CODE><BR><CODE>    method get_y : int</CODE><BR><CODE>  end</CODE><BR>

</PRE>
<BR>
<BR>
We cannot force the type of an instance of <TT>c2</TT> to be the type of
instances of <TT>c1</TT>:


<PRE><BR># <B>let</B><CODE> </CODE>a<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT><TT>(</TT><B>new</B><CODE> </CODE>c2<CODE> </CODE><CODE>0</CODE><CODE> </CODE><CODE>0</CODE><TT>)</TT><CODE> </CODE><CODE>:&gt;</CODE><CODE> </CODE>c1<TT>)</TT><CODE> </CODE>;;<BR><CODE>Characters 11-21:</CODE><BR><CODE>This expression cannot be coerced to type</CODE><BR><CODE>  c1 = &lt; eq : c1 -&gt; bool; get_x : int &gt;;</CODE><BR><CODE>it has type c2 = &lt; eq : c2 -&gt; bool; get_x : int; get_y : int &gt;</CODE><BR><CODE>but is here used with type &lt; eq : c1 -&gt; bool; get_x : int; get_y : int &gt;</CODE><BR><CODE>Type c2 = &lt; eq : c2 -&gt; bool; get_x : int; get_y : int &gt;</CODE><BR><CODE>is not compatible with type c1 = &lt; eq : c1 -&gt; bool; get_x : int &gt;</CODE><BR><CODE>Only the first object type has a method get_y</CODE><BR>

</PRE>
<BR>
<BR>
Types <I>c1</I> and <I>c2</I> are incompatible because the type of
<TT>eq</TT> in <TT>c2</TT> is not a subtype of the type of <TT>eq</TT> in
<TT>c1</TT>.
To see why this is true, let <EM>o1</EM> be an instance of
<I>c1</I>. If <EM>o21</EM> were an instance of <I>c2</I> subtyped to
<I>c1</I>, then since <EM>o21</EM> and <EM>o1</EM> would both be of type
<I>c1</I> the type of <TT>eq</TT> in <I>c2</I> would be a subtype
of the type of <TT>eq</TT> in <I>c1</I> and the expression
<EM>o21</EM><EM>#</EM><EM>eq(o1)</EM> would be correctly typed. But at run-time, since
<EM>o21</EM> is an instance of class <I>c2</I>, the method <TT>eq</TT> of
<I>c2</I> would be triggered. But this method would try to send the message
<TT>get_y</TT> to <EM>o1</EM>, which does not have such a method; our type
system would have failed!<BR>
<BR>
For our type system to fulfill its role, the subtyping
relation must be defined less na�vely. We do this in the next
paragraph.<BR>
<BR>

<H4> Formalization</H4><A NAME="subsubsec-formal"></A>
<H5> Subtyping between objects.</H5>
Let <I>t</I>=&lt;<I>m</I><SUB><FONT SIZE=2>1</FONT></SUB>:<FONT FACE=symbol>t</FONT><SUB><FONT SIZE=2>1</FONT></SUB>; ...  <I>m</I><SUB><FONT SIZE=2><I>n</I></FONT></SUB>: <FONT FACE=symbol>t</FONT><SUB><FONT SIZE=2><I>n</I></FONT></SUB>&gt;
and <I>t</I>'=&lt;<I>m</I><SUB><FONT SIZE=2>1</FONT></SUB>:<FONT FACE=symbol>s</FONT><SUB><FONT SIZE=2>1</FONT></SUB> ; ... ; <I>m</I><SUB><FONT SIZE=2><I>n</I></FONT></SUB>:<FONT FACE=symbol>s</FONT><SUB><FONT SIZE=2><I>n</I></FONT></SUB>; <I>m</I><SUB><FONT SIZE=2><I>n</I>+1</FONT></SUB>:<FONT FACE=symbol>s</FONT><SUB><FONT SIZE=2><I>n</I>+1</FONT></SUB>;
<I>etc</I>...&gt; we shall say that <I>t</I>' is a subtype of <I>t</I>, denoted by <I>t</I>' <FONT FACE=symbol>�</FONT>
<I>t</I>, if and only if <FONT FACE=symbol>s</FONT><SUB><FONT SIZE=2><I>i</I></FONT></SUB> <FONT FACE=symbol>�</FONT> <FONT FACE=symbol>t</FONT><SUB><FONT SIZE=2><I>i</I></FONT></SUB> for <I>i</I> <FONT FACE=symbol>�</FONT> {1,...,<I>n</I>}.<BR>
<BR>

<H5> Function call.</H5>
If <I>f</I> : <I>t</I> <FONT FACE=symbol>�</FONT> <I>s</I>, and if <I>a</I>:<I>t</I>' and <I>t</I>' <FONT FACE=symbol>�</FONT> <I>t</I> then (<I>f</I> <I>a</I>) is well
typed, and has type <I>s</I>.<BR>
<BR>
Intuitively, a function <I>f</I> expecting an argument of type <I>t</I> may safely receive
`an argument of a subtype <I>t</I>' of <I>t</I>.<BR>
<BR>

<H5> Subtyping of functional types.</H5>
Type <I>t</I>'<FONT FACE=symbol>�</FONT> <I>s</I>' is a subtype of <I>t</I><FONT FACE=symbol>�</FONT> <I>s</I>, denoted by
<I>t</I>'<FONT FACE=symbol>�</FONT> <I>s</I>' <FONT FACE=symbol>�</FONT> <I>t</I><FONT FACE=symbol>�</FONT> <I>s</I>, if and only if
<DIV ALIGN=center> <I>s</I>'<FONT FACE=symbol>�</FONT> <I>s</I>  and  <I>t</I> <FONT FACE=symbol>�</FONT> <I>t</I>' </DIV>
The relation <I>s</I>'<FONT FACE=symbol>�</FONT> <I>s</I> is called covariance, and the relation <I>t</I> <FONT FACE=symbol>�</FONT> <I>t</I>' is
called contravariance. Although surprising at first, this relation
between functional types can easily be justified in the context of
object-oriented programs with dynamic binding.<BR>
<BR>
<P>Let us assume that two classes <I>c</I>1 and <I>c</I>2 both have a method <I>m</I>.
Method <I>m</I> has type <I>t</I><SUB><FONT SIZE=2>1</FONT></SUB><FONT FACE=symbol>�</FONT> <I>s</I><SUB><FONT SIZE=2>1</FONT></SUB> in <I>c</I>1, and type
<I>t</I><SUB><FONT SIZE=2>2</FONT></SUB><FONT FACE=symbol>�</FONT> <I>s</I><SUB><FONT SIZE=2>2</FONT></SUB> in <I>c</I>2. For the sake of readability, let us denote by
<I>m</I><SUB><FONT SIZE=2>(1)</FONT></SUB> the method <I>m</I> of <I>c</I>1 and <I>m</I><SUB><FONT SIZE=2>(2)</FONT></SUB> that of <I>c</I>2. Finally, let us
assume <I>c</I>2<FONT FACE=symbol>�</FONT> <I>c</I>1, i.e. <I>t</I><SUB><FONT SIZE=2>2</FONT></SUB><FONT FACE=symbol>�</FONT> <I>s</I><SUB><FONT SIZE=2>2</FONT></SUB> <FONT FACE=symbol>�</FONT> <I>t</I><SUB><FONT SIZE=2>1</FONT></SUB><FONT FACE=symbol>�</FONT> <I>s</I><SUB><FONT SIZE=2>1</FONT></SUB>, and let us
look at a simple example of the covariance and contravariance relations.<BR>
<BR>
Let <I>g</I> : <I>s</I><SUB><FONT SIZE=2>1</FONT></SUB> <FONT FACE=symbol>�</FONT> <FONT FACE=symbol>a</FONT>, and
<I>h</I> (<I>o</I>:<I>c</I>1) (<I>x</I>:<I>t</I><SUB><FONT SIZE=2>1</FONT></SUB>) = <I>g</I>(<I>o</I>#<I>m</I>(<I>x</I>))<BR>
<BR>
<DL COMPACT=compact>
<DT>
Covariance:<DD> function <I>h</I> expects an object of type
 <I>c</I>1 as its first argument. Since <I>c</I>2<FONT FACE=symbol>�</FONT> <I>c</I>1, it is legal to pass it an object of type <I>c</I>2. Then
 the method invoked by <I>o</I>#<I>m</I>(<I>x</I>) is <I>m</I><SUB><FONT SIZE=2>(2)</FONT></SUB>, which returns a value of type
 <I>s</I><SUB><FONT SIZE=2>2</FONT></SUB>. Since this value is passed to <I>g</I> which expects an argument of type
 <I>s</I><SUB><FONT SIZE=2>1</FONT></SUB>, clearly we must have <I>s</I><SUB><FONT SIZE=2>2</FONT></SUB><FONT FACE=symbol>�</FONT> <I>s</I><SUB><FONT SIZE=2>1</FONT></SUB>.

<DT>Contravariance:<DD> for its second argument, <I>h</I> requires a value of
 type <I>t</I><SUB><FONT SIZE=2>1</FONT></SUB>. If, as above, we give <I>h</I> a first argument of type <I>c</I>2, then method
 <I>m</I><SUB><FONT SIZE=2>(2)</FONT></SUB> is invoked. Since it expects an argument of type <I>t</I><SUB><FONT SIZE=2>2</FONT></SUB>,
 <I>t</I><SUB><FONT SIZE=2>1</FONT></SUB><FONT FACE=symbol>�</FONT> <I>t</I><SUB><FONT SIZE=2>2</FONT></SUB>.
</DL><A NAME="toc213"></A>
<H3> Inclusion Polymorphism</H3> 
By ``polymorphism'' we mean the ability to apply a function to
arguments of any ``shape'' (type), or to send a message to objects of various
shapes.<BR>
<BR>
In the context of the functional/imperative kernel of the language, we have
already seen parameterized polymorphism, which enables you to apply a function
to arguments of arbitrary type. The polymorphic parameters of the function have
types containing type variables. A polymorphic function will execute the same
code for various types of parameters. To this end, it will not depend on the
structure of these arguments.<BR>
<BR>
The subtyping relation, used in conjunction with delayed binding, introduces a
new kind of polymorphism for methods: inclusion polymorphism. It lets
the same message be sent to instances of different types, provided they have been
constrained to the same subtype. Let us construct a list of points where some of
them are in fact colored points treated as points. Sending the same
message to all of them triggers the execution of different methods, depending
on the class of the receiving instance. This is called inclusion polymorphism because it
allows messages from class <TT>c</TT>, to be sent to any instance of
class <TT>sc</TT> that is a subtype of <TT>c</TT> (sc<CODE> </CODE><CODE>:&gt;</CODE><CODE> </CODE>c) that has been
constrained to <TT>c</TT>. Thus we obtain a polymorphic message passing for all
classes of the tree of subtypes of <TT>c</TT>. Contrary to parameterized
polymorphism, the code which is executed may be different for these instances.<BR>
<BR>
Thanks to parameterized classes, both forms of polymorphism can be used together.<BR>
<BR>
<A NAME="toc214"></A>
<H3> Equality between Objects</H3><A NAME="sec-eq-object"></A>
Now we can explain the somewhat surprising behavior of structural equality
between objects which was presented on page <A HREF="book-ora140.html#war-egalite-objet">??</A>. Two objects
are structurally equal when they are physically the same.


<PRE><BR># <B>let</B><CODE> </CODE>p1<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>2</CODE><TT>)</TT>;;<BR><CODE>val p1 : point = &lt;obj&gt;</CODE><BR># p1<CODE> </CODE><CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>2</CODE><TT>)</TT>;;<BR><CODE>- : bool = false</CODE><BR># p1<CODE> </CODE><CODE>=</CODE><CODE> </CODE>p1;;<BR><CODE>- : bool = true</CODE><BR>

</PRE>
<BR>
<BR>
This comes from the subtyping relation. Indeed we can try to compare an
instance <TT>o2</TT> of a class <I>sc</I> that is a subtype of <I>c</I>, constrained
to <I>c</I>, with an instance of <TT>o1</TT> from class <I>c</I>. If the
fields which are common to these two instances are equal, then these objects
might be considered as equal. This is wrong from a structural point of view
because <TT>o2</TT> could have additional fields. Therefore Objective CAML considers
that two objects are structurally different when they are physically
different.<BR>
<BR>


<PRE><BR># <B>let</B><CODE> </CODE>pc1<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>new</B><CODE> </CODE>colored_point<CODE> </CODE><TT>(</TT><CODE>1</CODE><CODE>,</CODE><CODE>2</CODE><TT>)</TT><CODE> </CODE><CODE>"red"</CODE>;;<BR><CODE>val pc1 : colored_point = &lt;obj&gt;</CODE><BR># <B>let</B><CODE> </CODE>q<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>pc1<CODE> </CODE><CODE>:&gt;</CODE><CODE> </CODE>point<TT>)</TT>;;<BR><CODE>val q : point = &lt;obj&gt;</CODE><BR># p1<CODE> </CODE><CODE>=</CODE><CODE> </CODE>q;;<BR><CODE>- : bool = false</CODE><BR>

</PRE>

This restrictive view of equality guarantees that an answer <TT>true</TT> is
not wrong, but an answer <TT>false</TT> guarantees nothing.<BR>
<BR>
<HR>
<A HREF="book-ora143.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora145.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
